 
  

 






<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html>

<!-- Mirrored from www.javapractices.com/topic/TopicAction.do?Id=152 by HTTrack Website Copier/3.x [XR&CO'2010], Sun, 12 Jun 2011 17:28:07 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=UTF-8"><!-- /Added by HTTrack -->
<head>
 <title>
  Java Practices -> Swing utility tasks
 </title>
 <link rel="stylesheet" type="text/css" href="../stylesheet8.css" media="all">
 
 <link rel="shortcut icon" href='../images/favicon.ico' type="image/vnd.microsoft.icon">
 <meta name="description" content="Concise presentations of java programming practices, tasks, and conventions, amply illustrated with syntax highlighted code examples.">
 
 <meta name='keywords' content='border,button,center,GridBagConstraints,icon,UiUtil,swing,java,java programming,java practices,java idiom,java style,java design patterns,java coding conventions,'>
 
 
</head>
 
<body>


<div class='menu-bar'>
 
  <a href='../home/HomeAction.html' title='Table of Contents'>Home</a> |
  <a href='../vote/VoteSummaryAction-2.html' title='View Poll Results'>Poll</a> |
   
  <A href='../feedback/FeedbackAction451f-2.html?Operation=Show' title='Send Your Feedback'>Wiki</a> |
  <b><a href='../source/SourceAction-2.html' title='Grab Source Code'>Source Code</a></b><IMG class='no-margin' SRC="../images/goldstar.gif" ALT=""> |

  <a href='http://www.web4j.com/Java_Web_Application_Framework_Overview.jsp?From=1' title='Free Download - Java Web Application Framework'><b>WEB4J</b></a> |
  
  <a href='http://www.date4j.net/' title='Replacement for java.util.Date'><b>DATE4J</b></a> |

   <a href='../references/ReferencesAction-2.html' title='References'>Links</a>
   
  <form action='http://www.javapractices.com/search/SearchAction.do' method='get' class='search-form'>
   <input type='text' name='SearchTerms' value="" size=12 maxlength=50 class='search'>
   <input type='submit' value="Search">
  </form>
 
</div>

<P>



  

 






<p class="display-messages">

 

 

</p>


<div class="main-layout">
 
   

 




<div class='page-title'>Swing utility tasks</div>

<div class='main-body'>
 
<br>A utility class which collects common tasks can greatly reduce code
duplication. This is especially true for Swing, where many elements of
GUI construction are repetitive.
<p><b>Extended Example</b>

<p>This utility class has methods for :
<ul>
<li>
centering windows on the screen, or with respect to a parent window</li>

<li>
equalizing sizes of components</li>

<li>
imposing an alignment on all items in a <tt>Box</tt></li>

<li>
creating borders of a standard size</li>

<li>
creating dialog titles of a standard format</li>

<li>
retrieving images</li>

<li>
creating pairs of components, both for user input (<tt>JLabel</tt> and
<tt>JTextField</tt>)
and simple display (two <tt>JLabel</tt> objects)</li>

<li>
using <tt>GridBagConstraints</tt> in a concise manner</li>

<li>
formatting numbers, times, and percents</li>
</ul>
<br>
<PRE>

<span class='keyword'>package</span> hirondelle.stocks.util.ui;

<span class='keyword'>import</span> hirondelle.stocks.util.Args;
<span class='keyword'>import</span> hirondelle.stocks.util.Consts;
<span class='keyword'>import</span> hirondelle.stocks.util.Util;

<span class='keyword'>import</span> java.util.*;
<span class='keyword'>import</span> java.text.*;
<span class='keyword'>import</span> java.net.URL;
<span class='keyword'>import</span> javax.swing.*;
<span class='keyword'>import</span> javax.swing.border.Border;
<span class='keyword'>import</span> java.awt.*;
<span class='keyword'>import</span> javax.swing.plaf.metal.MetalLookAndFeel;
<span class='keyword'>import</span> hirondelle.stocks.preferences.GeneralLookPreferencesEditor;

<span class='comment'>/** Static convenience methods for GUIs which eliminate code duplication.*/</span>
<span class='keyword'>public</span> <span class='keyword'>final</span> <span class='keyword'>class</span> UiUtil {

  <span class='comment'>/**
  * &lt;tt&gt;pack&lt;/tt&gt;, center, and &lt;tt&gt;show&lt;/tt&gt; a window on the screen.
  *
  * &lt;P&gt;If the size of &lt;tt&gt;aWindow&lt;/tt&gt; exceeds that of the screen, 
  * then the size of &lt;tt&gt;aWindow&lt;/tt&gt; is reset to the size of the screen.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> <span class='keyword'>void</span> centerAndShow(Window aWindow){
    <span class='comment'>//note that the order here is important
</span>    
    aWindow.pack();
    <span class='comment'>/*
     * If called from outside the event dispatch thread (as is 
     * the case upon startup, in the launch thread), then 
     * in principle this code is not thread-safe: once pack has 
     * been called, the component is realized, and (most) further
     * work on the component should take place in the event-dispatch 
     * thread. 
     *
     * In practice, it is exceedingly unlikely that this will lead 
     * to an error, since invisible components cannot receive events.
     */</span>
    Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension window = aWindow.getSize();
    <span class='comment'>//ensure that no parts of aWindow will be off-screen
</span>    <span class='keyword'>if</span> (window.height &gt; screen.height) {
      window.height = screen.height;
    }
    <span class='keyword'>if</span> (window.width &gt; screen.width) {
      window.width = screen.width;
    }
    <span class='keyword'>int</span> xCoord = (screen.width/<span class='literal'>2</span> - window.width/<span class='literal'>2</span>);
    <span class='keyword'>int</span> yCoord = (screen.height/<span class='literal'>2</span> - window.height/<span class='literal'>2</span>);
    aWindow.setLocation( xCoord, yCoord );
   
    aWindow.show();
  }
  
  <span class='comment'>/**
  * A window is packed, centered with respect to a parent, and then shown.
  *
  * &lt;P&gt;This method is intended for dialogs only.
  *
  * &lt;P&gt;If centering with respect to a parent causes any part of the dialog 
  * to be off screen, then the centering is overidden, such that all of the 
  * dialog will always appear fully on screen, but it will still appear 
  * near the parent.
  *
  * @param aWindow must have non-null result for &lt;tt&gt;aWindow.getParent&lt;/tt&gt;.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> <span class='keyword'>void</span> centerOnParentAndShow(Window aWindow){
    aWindow.pack();
    
    Dimension parent = aWindow.getParent().getSize();
    Dimension window = aWindow.getSize();
    <span class='keyword'>int</span> xCoord = 
      aWindow.getParent().getLocationOnScreen().x + 
     (parent.width/<span class='literal'>2</span> - window.width/<span class='literal'>2</span>)
    ;
    <span class='keyword'>int</span> yCoord = 
      aWindow.getParent().getLocationOnScreen().y + 
      (parent.height/<span class='literal'>2</span> - window.height/<span class='literal'>2</span>)
    ;
    
    <span class='comment'>//Ensure that no part of aWindow will be off-screen
</span>    Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    <span class='keyword'>int</span> xOffScreenExcess = xCoord + window.width - screen.width;
    <span class='keyword'>if</span> ( xOffScreenExcess &gt; <span class='literal'>0</span> ) {
      xCoord = xCoord - xOffScreenExcess;
    }
    <span class='keyword'>if</span> (xCoord &lt; <span class='literal'>0</span> ) {
      xCoord = <span class='literal'>0</span>;
    }
    <span class='keyword'>int</span> yOffScreenExcess = yCoord + window.height - screen.height;
    <span class='keyword'>if</span> ( yOffScreenExcess &gt; <span class='literal'>0</span> ) {
      yCoord = yCoord - yOffScreenExcess;
    }
    <span class='keyword'>if</span> (yCoord &lt; <span class='literal'>0</span>) {
      yCoord = <span class='literal'>0</span>;
    }
    
    aWindow.setLocation( xCoord, yCoord );
    aWindow.show();
  }

  <span class='comment'>/**
  * Return a border of dimensions recommended by the Java Look and Feel 
  * Design Guidelines, suitable for many common cases.
  *
  *&lt;P&gt;Each side of the border has size {@link UiConsts#STANDARD_BORDER}.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> Border getStandardBorder(){
    <span class='keyword'>return</span> BorderFactory.createEmptyBorder(
      UiConsts.STANDARD_BORDER, 
      UiConsts.STANDARD_BORDER, 
      UiConsts.STANDARD_BORDER, 
      UiConsts.STANDARD_BORDER
    );
  }

  <span class='comment'>/**
  * Return text which conforms to the Look and Feel Design Guidelines 
  * for the title of a dialog : the application name, a colon, then 
  * the name of the specific dialog.
  *
  *&lt;P&gt;Example return value: &lt;tt&gt;StocksMonitor: Preferences&lt;/tt&gt;
  *
  * @param aSpecificDialogName must have visible content
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> String getDialogTitle(String aSpecificDialogName){
    Args.checkForContent(aSpecificDialogName);
    StringBuilder result = <span class='keyword'>new</span> StringBuilder(Consts.APP_NAME);
    result.append(<span class='literal'>": "</span>);
    result.append(aSpecificDialogName);
    <span class='keyword'>return</span> result.toString(); 
  }
  
  <span class='comment'>/**
  * Make a horizontal row of buttons of equal size, whch are equally spaced, 
  * and aligned on the right.
  *
  * &lt;P&gt;The returned component has border spacing only on the top (of the size 
  * recommended by the Look and Feel Design Guidelines).
  * All other spacing must be applied elsewhere ; usually, this will only mean 
  * that the dialog's top-level panel should use {@link #getStandardBorder}.
  * 
  * @param aButtons contains the buttons to be placed in a row.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> JComponent getCommandRow(java.util.List&lt;JComponent&gt; aButtons){
    equalizeSizes( aButtons );
    JPanel panel = <span class='keyword'>new</span> JPanel();
    LayoutManager layout = <span class='keyword'>new</span> BoxLayout(panel, BoxLayout.X_AXIS);
    panel.setLayout( layout );
    panel.setBorder(  BorderFactory.createEmptyBorder(UiConsts.THREE_SPACES, <span class='literal'>0</span>, <span class='literal'>0</span>, <span class='literal'>0</span>) );
    panel.add( Box.createHorizontalGlue() );
    Iterator&lt;JComponent&gt; buttonsIter = aButtons.iterator();
    <span class='keyword'>while</span> ( buttonsIter.hasNext() ) {
      panel.add( buttonsIter.next() );
      <span class='keyword'>if</span> ( buttonsIter.hasNext() ) {
        panel.add( Box.createHorizontalStrut(UiConsts.ONE_SPACE) );
      }
    }
    <span class='keyword'>return</span> panel;
  }
  
  <span class='comment'>/**
  * Make a vertical row of buttons of equal size, whch are equally spaced, 
  * and aligned on the right.
  *
  * &lt;P&gt;The returned component has border spacing only on the left (of the size 
  * recommended by the Look and Feel Design Guidelines).
  * All other spacing must be applied elsewhere ; usually, this will only mean 
  * that the dialog's top-level panel should use {@link #getStandardBorder}.
  * 
  * @param aButtons contains the buttons to be placed in a column
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> JComponent getCommandColumn( java.util.List&lt;JComponent&gt; aButtons ){
    equalizeSizes( aButtons );
    JPanel panel = <span class='keyword'>new</span> JPanel();
    LayoutManager layout = <span class='keyword'>new</span> BoxLayout(panel, BoxLayout.Y_AXIS);
    panel.setLayout( layout );
    panel.setBorder(
      BorderFactory.createEmptyBorder(<span class='literal'>0</span>,UiConsts.THREE_SPACES, <span class='literal'>0</span>,<span class='literal'>0</span>)
    );
    <span class='comment'>//(no for-each is used here, because of the 'not-yet-last' check)
</span>    Iterator&lt;JComponent&gt; buttonsIter = aButtons.iterator();
    <span class='keyword'>while</span> ( buttonsIter.hasNext() ) {
      panel.add(buttonsIter.next());
      <span class='keyword'>if</span> ( buttonsIter.hasNext() ) {
        panel.add( Box.createVerticalStrut(UiConsts.ONE_SPACE) );
      }
    }
    panel.add( Box.createVerticalGlue() );
    <span class='keyword'>return</span> panel;
  }

  <span class='comment'>/**
  * Return an &lt;tt&gt;ImageIcon&lt;/tt&gt; using its &lt;tt&gt;String&lt;/tt&gt; identifier.
  *
  * @param aImageId starts with '/', and refers to an image resource 
  * which is accessible through {@link Class#getResource}.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> ImageIcon getImageIcon(String aImageId){
    <span class='keyword'>if</span>( ! aImageId.startsWith(BACK_SLASH) ){
      <span class='keyword'>throw</span> <span class='keyword'>new</span> IllegalArgumentException(
        <span class='literal'>"Image identifier does not start with backslash: "</span> + aImageId
      );
    }
    <span class='keyword'>return</span> fetchImageIcon(aImageId, UiUtil.<span class='keyword'>class</span>);
  }

  <span class='comment'>/**
  * Return an &lt;tt&gt;ImageIcon&lt;/tt&gt; using its &lt;tt&gt;String&lt;/tt&gt; identifier, relative to 
  * a given class.
  *
  * @param aImageId does NOT start with '/', and must refer to an image resource which is 
  * accessible through {@link Class#getResource}.
  * @param aClass the class relative to which the image is located.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> ImageIcon getImageIcon(String aImageId, Class&lt;?&gt; aClass){
    <span class='keyword'>if</span>( aImageId.startsWith(BACK_SLASH) ){
      <span class='keyword'>throw</span> <span class='keyword'>new</span> IllegalArgumentException(
        <span class='literal'>"Image identifier starts with a backslash: "</span> + aImageId
      );
    }
    <span class='keyword'>return</span> fetchImageIcon(aImageId, aClass);
  }
  
  <span class='comment'>/**
  * Return a square icon which paints nothing, and whose dimensions correspond 
  * to the user preference for icon size.
  *
  * &lt;P&gt;A common problem occurs with text alignment in menus, where there is 
  * a mixture of menu items with and without an icon. Adding an empty icon 
  * to menu items which do not have one will adjust its alignment to match 
  * that of the others which do have an icon.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> Icon getEmptyIcon(){
    GeneralLookPreferencesEditor prefs = <span class='keyword'>new</span> GeneralLookPreferencesEditor();
    <span class='keyword'>return</span> prefs.hasLargeIcons() ? EmptyIcon.SIZE_24 : EmptyIcon.SIZE_16;
  }
  
  <span class='comment'>/**
  * Return a &lt;tt&gt;Dimension&lt;/tt&gt; whose size is defined not in terms of pixels, 
  * but in terms of a given percent of the screen's width and height. 
  *
  *&lt;P&gt; Use to set the preferred size of a component to a certain 
  * percentage of the screen.  
  *
  * @param aPercentWidth percentage width of the screen, in range &lt;tt&gt;1..100&lt;/tt&gt;.
  * @param aPercentHeight percentage height of the screen, in range &lt;tt&gt;1..100&lt;/tt&gt;.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> <span class='keyword'>final</span> Dimension getDimensionFromPercent(
    <span class='keyword'>int</span> aPercentWidth, <span class='keyword'>int</span> aPercentHeight
   ){
    <span class='keyword'>int</span> low = <span class='literal'>1</span>;
    <span class='keyword'>int</span> high = <span class='literal'>100</span>;
    Args.checkForRange(aPercentWidth, low, high);
    Args.checkForRange(aPercentHeight, low, high);
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    <span class='keyword'>return</span> calcDimensionFromPercent(screenSize, aPercentWidth, aPercentHeight);
  }

  <span class='comment'>/**
   * Sets the items in &lt;tt&gt;aComponents&lt;/tt&gt; to the same size.
   *
   * &lt;P&gt;Sets each component's preferred and maximum sizes. 
   * The actual size is determined by the layout manager, whcih adjusts 
   * for locale-specific strings and customized fonts. (See this 
   * &lt;a href="http://java.sun.com/products/jlf/ed2/samcode/prefere.html"&gt;Sun doc&lt;/a&gt; 
   * for more information.)
   *
   * @param aComponents items whose sizes are to be equalized
   */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> <span class='keyword'>void</span> equalizeSizes(java.util.List&lt;JComponent&gt; aComponents) {
    Dimension targetSize = <span class='keyword'>new</span> Dimension(<span class='literal'>0</span>,<span class='literal'>0</span>);
    <span class='keyword'>for</span>(JComponent comp: aComponents ) {
      Dimension compSize = comp.getPreferredSize();
      <span class='keyword'>double</span> width = Math.max(targetSize.getWidth(), compSize.getWidth());
      <span class='keyword'>double</span> height = Math.max(targetSize.getHeight(), compSize.getHeight());
      targetSize.setSize(width, height);
    }
    setSizes(aComponents, targetSize);
  }
  
  <span class='comment'>/**
  * Create a pair of components, a &lt;tt&gt;JLabel&lt;/tt&gt; and an associated 
  * &lt;tt&gt;JTextField&lt;/tt&gt;, as is typically used for user input.
  *
  *&lt;P&gt;The &lt;tt&gt;JLabel&lt;/tt&gt; appears on the left, and the &lt;tt&gt;JTextField&lt;/tt&gt;
  * appears on the same  row, just to the right of the &lt;tt&gt;JLabel&lt;/tt&gt;. 
  * The &lt;tt&gt;JLabel&lt;/tt&gt; has a mnemonic which forwards focus to the 
  * &lt;tt&gt;JTextField&lt;/tt&gt; when activated.
  * 
  * @param aContainer holds the pair of components.
  * @param aName text of the &lt;tt&gt;JLabel&lt;/tt&gt; component.
  * @param aInitialValue possibly-null initial value to appear 
  * in the &lt;tt&gt;JTextField&lt;/tt&gt;; if &lt;tt&gt;null&lt;/tt&gt;, then 
  * &lt;tt&gt;JTextField&lt;/tt&gt; will be blank.
  * @param aMnemonic &lt;tt&gt;KeyEvent&lt;/tt&gt; field, used as the mnemonic for 
  * the &lt;tt&gt;JLabel&lt;/tt&gt;.
  * @param aConstraints applied to the &lt;tt&gt;JLabel&lt;/tt&gt;; the corresponding 
  * constraints for the &lt;tt&gt;JTextField&lt;/tt&gt; are the same as 
  * &lt;tt&gt;aConstraints&lt;/tt&gt;, except for &lt;tt&gt;gridx&lt;/tt&gt; being incremented by one; 
  * in addition, if &lt;tt&gt;aConstraints&lt;/tt&gt; has &lt;tt&gt;weightx=0&lt;/tt&gt; (the default),
  * then the entry field will receive &lt;tt&gt;weightx=1.0&lt;/tt&gt; (entry field gets more 
  * horizontal space upon resize).
  * @param aTooltip possibly-null text displayed as tool tip for the 
  * &lt;tt&gt;JTextField&lt;/tt&gt; ; if &lt;tt&gt;null&lt;/tt&gt;, the tool tip is turned off.
  * @return the user input &lt;tt&gt;JTextField&lt;/tt&gt;.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> JTextField addSimpleEntryField(
    Container aContainer, 
    String aName, 
    String aInitialValue, 
    <span class='keyword'>int</span> aMnemonic, 
    GridBagConstraints aConstraints,
    String aTooltip
  ){
    Args.checkForNull(aName);
    
    JLabel label = <span class='keyword'>new</span> JLabel(aName);
    label.setDisplayedMnemonic(aMnemonic);
    aContainer.add( label, aConstraints );

    JTextField result = <span class='keyword'>new</span> JTextField(UiConsts.SIMPLE_FIELD_WIDTH);
    label.setLabelFor(result);
    result.setToolTipText(aTooltip);
    <span class='keyword'>if</span> (aInitialValue != <span class='keyword'>null</span>) {
      result.setText(aInitialValue);
    }
    aConstraints.gridx = ++aConstraints.gridx;
    <span class='keyword'>if</span> (aConstraints.weightx == <span class='literal'>0.0</span>){
      aConstraints.weightx = <span class='literal'>1.0</span>;
    }
    aContainer.add(result, aConstraints);
    <span class='keyword'>return</span> result;
  }

  <span class='comment'>/**
  * Return a set of constraints with convenient default values.
  *
  *&lt;P&gt;Return constraints with these values :
  *&lt;ul&gt;
  * &lt;li&gt; &lt;tt&gt;gridx, gridy&lt;/tt&gt; - set to &lt;tt&gt;aX, aY&lt;/tt&gt;
  * &lt;li&gt; &lt;tt&gt;anchor - GridBagConstraints.WEST&lt;/tt&gt;
  * &lt;li&gt; &lt;tt&gt;insets - Insets(0,0,0, UiConsts.ONE_SPACE)&lt;/tt&gt;
  *&lt;/ul&gt;
  * 
  *&lt;P&gt; All other items simply take their default values :
  *&lt;ul&gt;
  * &lt;li&gt; &lt;tt&gt;fill - GridBagConstraints.NONE&lt;/tt&gt;
  * &lt;li&gt; &lt;tt&gt;gridwidth, gridheight - 0, 0&lt;/tt&gt; 
  * &lt;li&gt; &lt;tt&gt;weightx , weighty - 0, 0&lt;/tt&gt;
  * &lt;li&gt; &lt;tt&gt;ipadx, ipady - 0, 0&lt;/tt&gt;
  *&lt;/ul&gt;
  *
  * &lt;P&gt;The caller is free to change the returned constraints, to customize for 
  * their particular needs.
  *
  * @param aY in range &lt;tt&gt;0..10&lt;/tt&gt;.
  * @param aX in range &lt;tt&gt;0..10&lt;/tt&gt;.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> GridBagConstraints getConstraints(<span class='keyword'>int</span> aY, <span class='keyword'>int</span> aX){
    <span class='keyword'>int</span> low = <span class='literal'>0</span>;
    <span class='keyword'>int</span> high = <span class='literal'>10</span>;
    Args.checkForRange(aY, low, high);
    Args.checkForRange(aX, low, high);
    GridBagConstraints result = <span class='keyword'>new</span> GridBagConstraints();
    result.gridy = aY;
    result.gridx = aX;
    result.anchor = GridBagConstraints.WEST;
    result.insets = <span class='keyword'>new</span> Insets(<span class='literal'>0</span>,<span class='literal'>0</span>,<span class='literal'>0</span>,UiConsts.ONE_SPACE);
    <span class='keyword'>return</span> result;
  }

  <span class='comment'>/**
  * Return {@link #getConstraints(int, int)}, with the addition of setting 
  * &lt;tt&gt;gridwidth&lt;/tt&gt; to &lt;tt&gt;aWidth&lt;/tt&gt;, and setting 
  * &lt;tt&gt;gridheight&lt;/tt&gt; to &lt;tt&gt;aHeight&lt;/tt&gt;.
  *
  * &lt;P&gt;The caller is free to change the returned constraints, to customize for
  * their particular needs.
  *
  * @param aY in range &lt;tt&gt;0..10&lt;/tt&gt;.
  * @param aX in range &lt;tt&gt;0..10&lt;/tt&gt;.
  * @param aWidth in range &lt;tt&gt;1..10&lt;/tt&gt;.
  * @param aHeight in range &lt;tt&gt;1..10&lt;/tt&gt;.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> GridBagConstraints getConstraints(<span class='keyword'>int</span> aY, <span class='keyword'>int</span> aX, <span class='keyword'>int</span> aWidth, <span class='keyword'>int</span> aHeight){
    <span class='keyword'>int</span> low = <span class='literal'>0</span>;
    <span class='keyword'>int</span> high = <span class='literal'>10</span>;
    Args.checkForRange(aHeight, low, high);
    Args.checkForRange(aWidth, low, high);
    GridBagConstraints result = getConstraints(aY, aX);
    result.gridheight = aHeight;
    result.gridwidth = aWidth;
    <span class='keyword'>return</span> result;
  }
  
  <span class='comment'>/**
  * Create a pair of &lt;tt&gt;JLabel&lt;/tt&gt; components, as is typically needed 
  * for display of a name-value pair.
  *
  * &lt;P&gt;The name appears on the left, and the value appears on the right, 
  * all on the same row. A colon and an empty space are appended to the name. 
  * 
  * &lt;P&gt; If the the length of "value" label is greater than 
  * {@link UiConsts#MAX_LABEL_LENGTH}, then the text is truncated, an ellipsis
  * is placed at its end, and the full text is placed in a tooltip.
  * 
  * @param aContainer holds the pair of components.
  * @param aName text of the name &lt;tt&gt;JLabel&lt;/tt&gt;.
  * @param aValue possibly-null ; if null, then an empty &lt;tt&gt;String&lt;/tt&gt;
  * is used for the value; otherwise &lt;tt&gt;Object.toString&lt;/tt&gt; is used.
  * @param aConstraints for the name &lt;tt&gt;JLabel&lt;/tt&gt;; the corresponding 
  * constraints for the value &lt;tt&gt;JLabel&lt;/tt&gt; are mostly taken from 
  * &lt;tt&gt;aConstraints&lt;/tt&gt;, except for &lt;tt&gt;gridx&lt;/tt&gt; being incremented by one
  * (&lt;tt&gt;weightx&lt;/tt&gt; may differ as well - see &lt;tt&gt;aWeightOnDisplay&lt;/tt&gt;.)
  * @param aWeightOnDisplay if true, then set &lt;tt&gt;weightx&lt;/tt&gt; for the value 
  * field to 1.0 (to give it more horizontal space upon resize).
  * @return the &lt;tt&gt;JLabel&lt;/tt&gt; for the value (which is usually variable).
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> JLabel addSimpleDisplayField(
    Container aContainer, 
    String aName, 
    Object aValue, 
    GridBagConstraints aConstraints,
    <span class='keyword'>boolean</span> aWeightOnDisplay
  ){
    StringBuilder formattedName = <span class='keyword'>new</span> StringBuilder(aName);
    formattedName.append(<span class='literal'>": "</span>);
    JLabel name = <span class='keyword'>new</span> JLabel( formattedName.toString() );
    aContainer.add( name, aConstraints );
    
    String valueText = (aValue != <span class='keyword'>null</span>? aValue.toString() : Consts.EMPTY_STRING);
    JLabel value = <span class='keyword'>new</span> JLabel(valueText);
    truncateLabelIfLong(value);
    aConstraints.gridx = ++aConstraints.gridx;
    <span class='keyword'>if</span> (aWeightOnDisplay){
      aConstraints.weightx = <span class='literal'>1.0</span>;
    }
    aContainer.add( value, aConstraints );
    
    <span class='keyword'>return</span> value;
  }
  
  <span class='comment'>/**
  * Present a number of read-only items to the user as a vertical listing 
  * of &lt;tt&gt;JLabel&lt;/tt&gt; name-value pairs.
  *
  * &lt;P&gt;Each pair is added in the style of 
  * {@link #addSimpleDisplayField} (its &lt;tt&gt;aConstraints&lt;/tt&gt; param are those 
  * returned by {@link #getConstraints(int, int)}, and its &lt;tt&gt;aWeightOnDisplay&lt;/tt&gt; 
  * param is set to &lt;tt&gt;true&lt;/tt&gt;).
  *
  * &lt;P&gt;The order of presentation is determined by the iteration order of 
  * &lt;tt&gt;aNameValuePairs&lt;/tt&gt;.
  *
  *&lt;P&gt;The number of items which should be presented using this method is limited, since
  * no scrolling mechanism is given to the user.
  *
  * @param aContainer holds the display fields.
  * @param aNameValuePairs has &lt;tt&gt;String&lt;/tt&gt; keys for the names, 
  * and values are possibly null &lt;tt&gt;Object&lt;/tt&gt;s; 
  * if null, then an empty &lt;tt&gt;String&lt;/tt&gt; is displayed, otherwise
  * &lt;tt&gt;Object.toString&lt;/tt&gt; is called on the value and displayed.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> <span class='keyword'>void</span> addSimpleDisplayFields(
    Container aContainer, Map&lt;String, String&gt; aNameValuePairs
  ) {
    Set&lt;String&gt; keys = aNameValuePairs.keySet();
    <span class='keyword'>int</span> rowIdx = <span class='literal'>0</span>;
    <span class='keyword'>for</span>(String name: keys) {
      String value = aNameValuePairs.get(name);
      <span class='keyword'>if</span>(value == <span class='keyword'>null</span>){
        value = Consts.EMPTY_STRING;
      }
      UiUtil.addSimpleDisplayField(
        aContainer, 
        name, 
        value, 
        UiUtil.getConstraints(rowIdx,<span class='literal'>0</span>),
        <span class='keyword'>true</span>
      );
      ++rowIdx;
    }
  }
 
  <span class='comment'>/**
  * Adds "glue" (an empty component with desired resizing behavior) to the bottom 
  * row of a &lt;tt&gt;GridBagLayout&lt;/tt&gt; of components. When resized, this glue will 
  * take up extra vertical space.
  *
  * &lt;P&gt;This method is especially useful for text data presented in a listing or 
  * tabular form. Such components naturally resize horizontally, while their vertical 
  * resizing should often be absent. If such a listing is resized vertically, then this 
  * glue can take up the remaining vertical space, keeping the text at the top.
  *
  * @param aPanel uses &lt;tt&gt;GridBagLayout&lt;/tt&gt;, and contains components whose 
  * &lt;tt&gt;weighty&lt;/tt&gt; values are all 0.0 (the default).
  * @param aLastRowIdx index of the last row of components, in which the glue will be
  * placed.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> <span class='keyword'>void</span> addVerticalGridGlue(JPanel aPanel, <span class='keyword'>int</span> aLastRowIdx) {   
    GridBagConstraints glueConstraints = UiUtil.getConstraints(aLastRowIdx,<span class='literal'>0</span>);
    glueConstraints.weighty = <span class='literal'>1.0</span>;
    glueConstraints.fill = GridBagConstraints.VERTICAL;
    aPanel.add( <span class='keyword'>new</span> JLabel(), glueConstraints );
  }
  
  <span class='comment'>/**
  * Return a &lt;tt&gt;String&lt;/tt&gt;, suitable for presentation to the end user, 
  * representing a percentage having two decimal places, using the default locale.
  *
  * &lt;P&gt;An example return value is "5.15%". The intent of this method is to 
  * provide a standard representation and number of decimals for the entire 
  * application. If a different number of decimal places is required, then 
  * the caller should use &lt;tt&gt;NumberFormat&lt;/tt&gt; instead.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> String getLocalizedPercent( Number aNumber ){
    NumberFormat localFormatter = NumberFormat.getPercentInstance();
    localFormatter.setMinimumFractionDigits(<span class='literal'>2</span>);
    <span class='keyword'>return</span> localFormatter.format( aNumber.doubleValue() );
  }
  
  <span class='comment'>/**
  * Return a &lt;tt&gt;String&lt;/tt&gt;, suitable for presentation to the end user, 
  * representing an integral number with no decimal places, using the default 
  * locale.
  *
  * &lt;P&gt;An example return value is "8,000". The intent of this method is to 
  * provide a standard representation of integers for the entire 
  * application.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> String getLocalizedInteger( Number aNumber ) {
    NumberFormat localFormatter = NumberFormat.getNumberInstance();
    <span class='keyword'>return</span> localFormatter.format( aNumber.intValue() );
  }

  <span class='comment'>/**
  * Return a &lt;tt&gt;String&lt;/tt&gt;, suitable for presentation to the end user, 
  * representing a date in &lt;tt&gt;DateFormat.SHORT&lt;/tt&gt; and the default locale.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> String getLocalizedTime(Date aDate){
    DateFormat dateFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
    <span class='keyword'>return</span> dateFormat.format(aDate);
  }

  <span class='comment'>/**
  * Make the sytem emit a beep.
  *
  * &lt;P&gt;May not beep unless the speakers are turned on, so this cannot 
  * be guaranteed to work.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> <span class='keyword'>void</span> beep(){
    Toolkit.getDefaultToolkit().beep();
  }

  <span class='comment'>/**
  * An alternative to multi-line labels, for the presentation of 
  * several lines of text, and for which the line breaks are determined 
  * solely by the widget.
  *
  * @param aText must have visible content, doesn't contain newline characters or html.
  * @return &lt;tt&gt;JTextArea&lt;/tt&gt; which is not editable, has improved spacing over the 
  * supplied default (placing {@link UiConsts#ONE_SPACE} on the left and right), 
  * which wraps lines on word boundaries, and whose background color is the 
  * same as {@link javax.swing.plaf.metal.MetalLookAndFeel#getMenuBackground}.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> JTextArea getStandardTextArea(String aText){
    Args.checkForContent(aText);
    <span class='keyword'>if</span> ( aText.indexOf(Consts.NEW_LINE) != -<span class='literal'>1</span> ){
      <span class='keyword'>throw</span> <span class='keyword'>new</span> IllegalArgumentException(<span class='literal'>"Must not contain new line characters: "</span> + aText);
    }
    JTextArea result = <span class='keyword'>new</span> JTextArea(aText);
    result.setEditable(<span class='keyword'>false</span>);
    result.setWrapStyleWord(<span class='keyword'>true</span>);
    result.setLineWrap(<span class='keyword'>true</span>);
    result.setMargin( <span class='keyword'>new</span> Insets(<span class='literal'>0</span>,UiConsts.ONE_SPACE,<span class='literal'>0</span>,UiConsts.ONE_SPACE) );
    <span class='comment'>//this is a bit hacky: the desired color is "secondary3", but cannot see how 
</span>    <span class='comment'>//to reference it directly; hence, an element which uses secondary3 is used instead.
</span>    result.setBackground( MetalLookAndFeel.getMenuBackground() ); 
    
    <span class='keyword'>return</span> result;
  }
  
  <span class='comment'>/**
  * An alternative to multi-line labels, for the presentation of 
  * several lines of text, and for which line breaks are determined 
  * solely by &lt;tt&gt;aText&lt;/tt&gt;, and not by the widget.
  *
  * @param aText has visible content
  * @return &lt;tt&gt;JTextArea&lt;/tt&gt; which is not editable, has improved spacing over the 
  * supplied default (placing {@link UiConsts#ONE_SPACE} on the left and right), 
  * and whose background color is the same as 
  * {@link javax.swing.plaf.metal.MetalLookAndFeel#getMenuBackground}.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> JTextArea getStandardTextAreaHardNewLines(String aText){
    Args.checkForContent(aText);
    JTextArea result = <span class='keyword'>new</span> JTextArea(aText);
    result.setEditable(<span class='keyword'>false</span>);
    result.setMargin( <span class='keyword'>new</span> Insets(<span class='literal'>0</span>,UiConsts.ONE_SPACE,<span class='literal'>0</span>,UiConsts.ONE_SPACE) );
    result.setBackground( MetalLookAndFeel.getMenuBackground() ); 
    <span class='keyword'>return</span> result;
  }
  
  <span class='comment'>/**
  * Imposes a uniform horizontal alignment on all items in a container.
  *
  *&lt;P&gt; Intended especially for &lt;tt&gt;BoxLayout&lt;/tt&gt;, where all components need 
  * to share the same alignment in order for display to be reasonable. 
  * (Indeed, this method may only work for &lt;tt&gt;BoxLayout&lt;/tt&gt;, since apparently 
  * it is the only layout to use &lt;tt&gt;setAlignmentX, setAlignmentY&lt;/tt&gt;.)
  *
  * @param aContainer contains only &lt;tt&gt;JComponent&lt;/tt&gt; objects.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> <span class='keyword'>void</span> alignAllX(Container aContainer, UiUtil.AlignX aAlignment){
    java.util.List&lt;Component&gt; components = Arrays.asList( aContainer.getComponents() );
    <span class='keyword'>for</span>(Component comp: components){
      JComponent jcomp = (JComponent)comp;
      jcomp.setAlignmentX( aAlignment.getValue() );
    }
  }
  
  <span class='comment'>/** Enumeration for horizontal alignment. */</span>
  <span class='keyword'>public</span> <span class='keyword'>enum</span> AlignX {
    LEFT(Component.LEFT_ALIGNMENT),
    CENTER(Component.CENTER_ALIGNMENT),
    RIGHT(Component.RIGHT_ALIGNMENT);
    <span class='keyword'>public</span> <span class='keyword'>float</span> getValue(){
      <span class='keyword'>return</span> fValue;
    }
    <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>float</span> fValue;
    <span class='keyword'>private</span> AlignX(<span class='keyword'>float</span> aValue){
      fValue = aValue;
    }
  }
  
  <span class='comment'>/**
  * Imposes a uniform vertical alignment on all items in a container.
  *
  *&lt;P&gt; Intended especially for &lt;tt&gt;BoxLayout&lt;/tt&gt;, where all components need 
  * to share the same alignment in order for display to be reasonable.
  * (Indeed, this method may only work for &lt;tt&gt;BoxLayout&lt;/tt&gt;, since apparently 
  * it is the only layout to use &lt;tt&gt;setAlignmentX, setAlignmentY&lt;/tt&gt;.)
  *
  * @param aContainer contains only &lt;tt&gt;JComponent&lt;/tt&gt; objects.
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> <span class='keyword'>void</span> alignAllY(Container aContainer, UiUtil.AlignY aAlignment){
    java.util.List components = Arrays.asList( aContainer.getComponents() );
    Iterator compsIter = components.iterator();
    <span class='keyword'>while</span> ( compsIter.hasNext() ) {
      JComponent comp = (JComponent)compsIter.next();
      comp.setAlignmentY( aAlignment.getValue() );
    }
  }

  <span class='comment'>/** Type-safe enumeration vertical alignment. */</span>
  <span class='keyword'>public</span> <span class='keyword'>enum</span> AlignY {
    TOP(Component.TOP_ALIGNMENT),
    CENTER(Component.CENTER_ALIGNMENT),
    BOTTOM(Component.BOTTOM_ALIGNMENT);
    <span class='keyword'>float</span> getValue(){
      <span class='keyword'>return</span> fValue;
    }
    <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>float</span> fValue;
    <span class='keyword'>private</span> AlignY( <span class='keyword'>float</span> aValue){
      fValue = aValue;
    }
  }
  
  <span class='comment'>/**
  * Ensure that &lt;tt&gt;aRootPane&lt;/tt&gt; has no default button associated with it.
  *
  * &lt;P&gt;Intended mainly for dialogs where the user is confirming a delete action.
  * In this case, an explicit Yes or No is preferred, with no default action being 
  * taken when the user hits the Enter key. 
  */</span>
  <span class='keyword'>public</span> <span class='keyword'>static</span> <span class='keyword'>void</span> noDefaultButton(JRootPane aRootPane){
    aRootPane.setDefaultButton(<span class='keyword'>null</span>);
  }

  <span class='comment'>// PRIVATE //
</span>  
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> String BACK_SLASH = <span class='literal'>"/"</span>;

  <span class='comment'>/**
  * If &lt;tt&gt;aIconName&lt;/tt&gt; indicates that the icon is part of the standard graphic
  * repository (by starting with "/toolbar"), then append either "16.gif" or 
  * "24.gif" to the name, according to the user's current preference for icon size.
  */</span>
  <span class='keyword'>private</span> <span class='keyword'>static</span> String addSizeToStandardIcon(String aIconName){
    assert( Util.textHasContent(aIconName) );
    StringBuilder result = <span class='keyword'>new</span> StringBuilder(aIconName);
    <span class='keyword'>if</span> ( aIconName.startsWith(<span class='literal'>"/toolbar"</span>) ) {
      GeneralLookPreferencesEditor prefs = <span class='keyword'>new</span> GeneralLookPreferencesEditor();
      <span class='keyword'>if</span> ( prefs.hasLargeIcons() ) {
        result.append(<span class='literal'>"24.gif"</span>);
      }
      <span class='keyword'>else</span> {
        result.append(<span class='literal'>"16.gif"</span>);
      }
    }
    <span class='keyword'>return</span> result.toString();
  }

  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>void</span> setSizes(java.util.List aComponents, Dimension aDimension){
    Iterator compsIter = aComponents.iterator();      
    <span class='keyword'>while</span> ( compsIter.hasNext() ) {
      JComponent comp = (JComponent) compsIter.next();
      comp.setPreferredSize( (Dimension)aDimension.clone() );
      comp.setMaximumSize( (Dimension)aDimension.clone() );
    }
  }

  <span class='keyword'>private</span> <span class='keyword'>static</span> Dimension calcDimensionFromPercent(
    Dimension aSourceDimension, <span class='keyword'>int</span> aPercentWidth, <span class='keyword'>int</span> aPercentHeight
  ){
    <span class='keyword'>int</span> width = aSourceDimension.width * aPercentWidth/<span class='literal'>100</span>;
    <span class='keyword'>int</span> height = aSourceDimension.height * aPercentHeight/<span class='literal'>100</span>;
    <span class='keyword'>return</span> <span class='keyword'>new</span> Dimension(width, height);
  }

  <span class='comment'>/**
  * If aLabel has text which is longer than MAX_LABEL_LENGTH, then truncate 
  * the label text and place an ellipsis at the end; the original text is placed 
  * in a tooltip.
  *
  * This is particularly useful for displaying file names, whose length 
  * can vary widely between deployments.
  */</span>
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>void</span> truncateLabelIfLong(JLabel aLabel){
    String originalText = aLabel.getText();
    <span class='keyword'>if</span> (originalText.length() &gt; UiConsts.MAX_LABEL_LENGTH){
      aLabel.setToolTipText( originalText );
      String truncatedText = 
        originalText.substring(<span class='literal'>0</span>, UiConsts.MAX_LABEL_LENGTH) + Consts.ELLIPSIS
      ;
      aLabel.setText(truncatedText);
    }
  }
  
  <span class='keyword'>private</span> <span class='keyword'>static</span> ImageIcon fetchImageIcon(String aImageId, Class&lt;?&gt; aClass){
    String imgLocation = addSizeToStandardIcon(aImageId);
    URL imageURL = aClass.getResource(imgLocation);
    <span class='keyword'>if</span> ( imageURL != <span class='keyword'>null</span> ) {
      <span class='keyword'>return</span> <span class='keyword'>new</span> ImageIcon(imageURL);
    }
    <span class='keyword'>else</span> {
      <span class='keyword'>throw</span> <span class='keyword'>new</span> IllegalArgumentException(<span class='literal'>"Cannot retrieve image using id: "</span> + aImageId);
    }
  }
} 
</PRE>
<br>
<br>
<br>

</div>




<div class='topic-section'>See Also :</div>
<div class='main-body'>
 
  
  <a href='TopicAction992c-2.html?Id=148'>Look and Feel guidelines</a> <br>
 
  
  <a href='TopicActionff7e-2.html?Id=166'>Layout Managers</a> <br>
 
  
  <a href='TopicAction5c4c-2.html?Id=169'>Align menu items</a> <br>
 
</div>


<div class='topic-section'>Would you use this technique?</div>
<div class='main-body'>
  
  <form action="http://www.javapractices.com/vote/AddVoteAction.do" method='post'>
    Yes<input type='radio' name='Choice' value='Y' >
    &nbsp;&nbsp;No<input type='radio' name='Choice' value='N'>
    &nbsp;&nbsp;Undecided<input type='radio' name='Choice' value="?" >
    &nbsp;&nbsp;<input type=submit value="Vote" >
    <input type='hidden' name='Operation' value='Apply'>
    <input type='hidden' name='TopicId' value='152'>
  </form>
</div>

<div style='height:10.0em;'></div>

 
 
</div>

  

 





<div align='center' class='legalese'>  
&copy; 2011 Hirondelle Systems |
<a href='../source/SourceAction-2.html'><b>Source Code</b></a><IMG class='no-margin' SRC="../images/goldstar.gif" ALT=""> |
<a href="mailto:webmaster@javapractices.com">Contact</a> |
<a href="http://creativecommons.org/licenses/by-nc-sa/1.0/">License</a> |
<a href='../apps/cjp.rss'>RSS</a>
<!-- ukey="2AC36CD2" -->
<!-- ckey="16DF3D87" -->
<br>

 Individual code snippets can be used under this <a href='../LICENSE.txt'>BSD license</a> - Last updated on June 6, 2010.<br>
 Over 150,000 unique IPs last month - <span title='Java Practices 2.6.5, Mon May 16 00:00:00 EDT 2011'>Built with</span> <a href='http://www.web4j.com/'>WEB4J</a>.<br>
 - In Memoriam : Bill Dirani -
</div>

<script src="../../www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-2633428-1";
urchinTracker();
</script>



</body>

<!-- Mirrored from www.javapractices.com/topic/TopicAction.do?Id=152 by HTTrack Website Copier/3.x [XR&CO'2010], Sun, 12 Jun 2011 17:28:07 GMT -->
<!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=UTF-8"><!-- /Added by HTTrack -->
</html>
